﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;

namespace pigs
{
    public class Pig : pigs.DynamicObject
    {
        public bool isInvincible;
        public bool shouldEatSlop;
        public bool isEatingSlop;
        public bool escaped;
        public bool hitByFlame;
        public bool ghost;
        public int cooldown_ninja;

        public int START_HEALTH;
        public int START_DAMAGE;
        public float START_SPEED;
        public int VALUE;

        public bool lead;
        public bool buff;

        public Boolean shouldGhost;
        public Color color;

        // Keeps track of the vertical speed of a given pig
        public float vertSpeed;

        /// <summary>
        /// Constructor for a given pig
        /// </summary>
        /// <param name="texture"> The image to use as the pig
        /// <param name="position"> The position of the pig relative to the screen
        public Pig(Texture2D texture, Vector2 position):base(texture,position)
        {
            color = Color.White;
            shouldGhost = false;
        }

        /// <summary>
        /// Determines if the pig can see a player
        /// </summary>
        /// <param name="playerLocation">The location of the player on the screen</param>
        /// <param name="obstacles">The list of obstacles on the screen</param>
        /// <returns>True if the player is visible, false otherwise</returns>
        public Boolean PlayerVisible(Vector2 playerLocation, List<Scenery> obstacles)
        {
            bool isVisible = true;
            Line lineOfSight = new Line(playerLocation, this.position);
            
            foreach (Scenery o in obstacles)
            {
                if (lineOfSight.Intersects(o.rectangle)) { isVisible = false; }
            }
            //Console.Write("Player is visible = " + isVisible + "\n");
            return isVisible;
        }

        /// <summary>
        /// Determines if an obstacle is in the pigs line of sight
        /// </summary>
        /// <param name="obstacles">The list of obstacles on the screen</param>
        /// <returns>True if the pig sees an obstacle, false otherwise</returns>
        public String ObstacleVisible(List<Scenery> obstacles)
        {
            Vector2 lookAhead = new Vector2(this.position.X - 75, this.position.Y + this.texture.Height + 5);
            Line lineOfSight = new Line(lookAhead, this.position);

            foreach (Scenery o in obstacles)
            {
                if (lineOfSight.Intersects(o.rectangle))
                {
                    if (o.top)
                    {
                        return "top";
                    }
                    else
                    {
                        return "bottom";
                    }
                }

            }
            return "none";
        }

        /// <summary>
        /// Determines if an obstacle is in the pigs line of sight
        /// </summary>
        /// <param name="obstacles">The list of obstacles on the screen</param>
        /// <returns>True if the pig sees an obstacle, false otherwise</returns>
        public string ObstacleMove(List<Scenery> obstacles, string vert, Vector2 avoidGoal)
        {
            Vector2 lookAheadRightUp = new Vector2(this.position.X + (this.texture.Width / 5), this.position.Y - 8);
            Vector2 lookAheadLeftUp = new Vector2(this.position.X - 15, this.position.Y - 8);
            Vector2 lookAheadRight = new Vector2(this.position.X + (this.texture.Width / 5), this.position.Y + this.texture.Height + 8);
            Vector2 lookAheadLeft = new Vector2(this.position.X - 15, this.position.Y + this.texture.Height + 8);
            Line lineOfSightRightUp = new Line(lookAheadRightUp, this.position);
            Line lineofSightLeftUp = new Line(lookAheadLeftUp, this.position);
            Line lineOfSightRight = new Line(lookAheadRight, this.position);
            Line lineofSightLeft = new Line(lookAheadLeft, this.position);

            Line lineofSightAvoid = new Line(this.position, avoidGoal);

            if (this.ID.Equals("steel"))
            {
                lookAheadRightUp = new Vector2(this.position.X + this.texture.Width, this.position.Y - 8);
                lookAheadLeftUp = new Vector2(this.position.X - 15, this.position.Y - 8);
                lookAheadRight = new Vector2(this.position.X + this.texture.Width, this.position.Y + this.texture.Height + 8);
                lookAheadLeft = new Vector2(this.position.X - 15, this.position.Y + this.texture.Height + 8);
                lineOfSightRightUp = new Line(lookAheadRightUp, this.position);
                lineofSightLeftUp = new Line(lookAheadLeftUp, this.position);
                lineOfSightRight = new Line(lookAheadRight, this.position);
                lineofSightLeft = new Line(lookAheadLeft, this.position);

                lineofSightAvoid = new Line(this.position, avoidGoal);
            }

            if (vert.Equals("up"))
            {
                foreach (Scenery o in obstacles)
                {
                    if (o.top)
                    {
                        if (lineOfSightRightUp.Intersects(o.rectangle))
                        {
                            return "top";
                        }
                        if (lineofSightLeftUp.Intersects(o.rectangle))
                        {
                            return "top";
                        }
                    }
                }
                return "none";
            }
            else if (vert.Equals("down"))
            {
                foreach (Scenery o in obstacles)
                {
                    if (lineOfSightRight.Intersects(o.rectangle))
                    {
                          return "bottom";
                    }
                    if (lineofSightLeft.Intersects(o.rectangle))
                    {
                          return "bottom";
                    }
                }
            }
            else if (vert.Equals("avoid"))
            {
                foreach (Scenery o in obstacles)
                {
                    if (lineofSightAvoid.Intersects(o.rectangle))
                    {
                        if (o.top)
                        {
                            return "top";
                        }
                        else
                        {
                            return "bottom";
                        }
                    }
                }
            }
            else if (vert.Equals("lead"))
            {
                lookAheadRightUp = new Vector2(this.position.X + (this.texture.Width / 5), this.position.Y - 120);
                lookAheadLeftUp = new Vector2(this.position.X - 150, this.position.Y - 120);
                lookAheadRight = new Vector2(this.position.X + (this.texture.Width / 5), this.position.Y + this.texture.Height + 95);
                lookAheadLeft = new Vector2(this.position.X - 150, this.position.Y + this.texture.Height + 95);
                lineOfSightRightUp = new Line(lookAheadRightUp, this.position);
                lineofSightLeftUp = new Line(lookAheadLeftUp, this.position);
                lineOfSightRight = new Line(lookAheadRight, this.position);
                lineofSightLeft = new Line(lookAheadLeft, this.position);
                foreach (Scenery o in obstacles)
                {
                    if (lineOfSightRight.Intersects(o.rectangle) || lineofSightLeft.Intersects(o.rectangle))
                    {
                        return "top";
                    }
                    if (lineOfSightRightUp.Intersects(o.rectangle) || lineofSightLeftUp.Intersects(o.rectangle))
                    {
                        return "bottom";
                    }
                }
            }
            return "none";
        }

        // The doAI function for the pigs, should be implemented in each _____pig.cs file, its not yet
        public virtual void doAI()
        {
        }

        //The pushback method for the steel pig
        public virtual void pushBack() { }


        // Need to see if there is a way to just call update from level instead of basicUpdate
        /// <summary>
        /// This is the update method for the basic pig.
        /// </summary>
        /// <param name="gameTime"> The current game time
        /// <param name="p"> The parameters for a steel pig if it is present
        /// <param name="steelPig"> Whether or not a steel pig is active
        /// <param name="pigs"> The list of all other pigs
        /// <param name="obstacles"> The list of all obstacles
        public virtual void basicUpdate(GameTime gameTime, pigs.Pig p, bool steelPig, List<Pig> pigs, List<Scenery> obstacles)
        {
        }

        /// <summary>
        /// This is the update method for the bunny pig.
        /// </summary>
        /// <param name="gameTime"> The current game time
        /// <param name="obstacles"> The list of all obstacles
        public virtual bool bunnyUpdate(GameTime gameTime, List<Scenery> obstacles, List<Pig> pigs, bool leadPig, pigs.Pig p)
        {
            return false;
        }

        /// <summary>
        /// Drunk pig don't give a shit
        /// </summary>
        public virtual void drunkUpdate(GameTime gameTime)
        {
        }

        public virtual bool ninjaUpdate(GameTime gameTime, List<Pigs.Weapons.Bullet> bullets, List<pigs.Scenery> obstacles, List<Pig> pigs)
        {
            return false;
        }

        public virtual void magicUpdate(GameTime gameTime, List<Scenery> obstacles, List<Player> players, List<Pig> pigs, bool steelPig)
        {
        }

        public virtual void leaderUpdate(GameTime gameTime, List<Scenery> obstacles, List<Pig> pigs)
        {
        }

        public virtual void steelUpdate(GameTime gameTime, List<Scenery> obstacles, int playerY)
        {
        }

        public virtual void suiUpdate(GameTime gameTime, List<pigs.Scenery> obstacles, Vector2 pos)
        {
        } 

        public bool avoidScenery(List<Scenery> obstacles)
        {
            // Overwrite any basic pig AI by saying "If I can see a mountain ___ distance ahead of me, slow down and move up"
            if (ObstacleVisible(obstacles).Equals("bottom"))
            {
                this.position.Y -=  3 * START_SPEED / 2;
                this.position.X -= 2 * START_SPEED / 3;
                return true;
            }
            else if (ObstacleVisible(obstacles).Equals("top"))
            {
                this.position.Y += 3 * START_SPEED / 2;
                this.position.X -= 2 * START_SPEED / 3;
                return true;
            }
            return false;
            // Otherwise, follow AI
        }

        public void makeGhost()
        {
            shouldGhost = true;
        }

        public override void Draw(SpriteBatch spriteBatch)
        {
            spriteBatch.Draw(this.texture, this.position, null, color, 0f, Vector2.Zero, 1f, effect, 0f);
        }

        public void gohome(List<Scenery> obstacles)
        {

            if (Math.Abs(this.position.Y - this.startY) < 5)
            {
            }
            else if (this.position.Y < this.startY)
            {
                if (ObstacleMove(obstacles, "down", this.position).Equals("none"))
                {
                    this.position.Y += 2;
                }
            }
            else if (this.position.Y > this.startY)
            {
                if (ObstacleMove(obstacles, "up", this.position).Equals("none"))
                {
                    this.position.Y -= 2;
                }
            }
        }

        public void followSteel(Pig p)
        {
            // If a given pig is a little infront of a steel pig or isn't behind it, then slow it down to let the steel
            // pig catch up
            if ((this.position.X > (p.position.X - 75)) && !(this.position.X > (p.position.X + p.texture.Width)))
            {
                this.speed = this.speed - 0.05f;
                // Basic pigs will ignore slop if they can get behind a steel pig
                this.shouldEatSlop = false;
            }
            // Otherwise, if a given pig is slightly behind a steel pig
            else if (this.position.X > (p.position.X + p.texture.Width + 10))
            {
                this.shouldEatSlop = false;
                // If a given pig is within a short distance of the rear of a steel pig then slow down to match the steel pig's speed
                if (this.position.X < ((p.position.X + p.texture.Width) + 30))
                {
                    if (this.speed > p.speed)
                    {
                        this.speed = -0.05f;
                    }
                }
                // If a given pig is behind but too far from a steel pig, speed up to catch up to it
                if ((this.position.X >= ((p.position.X + p.texture.Width) + 30)) && (this.speed < this.START_SPEED))
                {
                    this.speed += .1f;
                }
            }
            // In this case, a steel pig is active, but a pig is too far ahead to be influenced, so make sure that it will eat slop
            else
            {
                this.shouldEatSlop = true;
            }

            // If a pig would be influenced by a steel pig, set the appropriate y speeds 
            if (this.position.X > (p.position.X - 50))
            {
                // If a pig is below the steel pig, move it up
                if (this.position.Y > (p.position.Y + (p.texture.Height * 1 / 2)))
                {
                    this.position.Y -= 2;
                }
                // If a pig is above the steel pig, move it down
                else if (this.position.Y < (p.position.Y))
                {
                    this.position.Y += 2;
                }
            }
        }

        public void avoidSuicide(List<Pig> pigs, List<Scenery> obstacles)
        {
            bool foundSuicide = false;
            // Iterate through all the other pigs, and find any nearby suicide pigs.
            foreach (pigs.Pig q in pigs)
            {
                // As long as you haven't found a suicide pig in range yet, keep checking
                if (!foundSuicide)
                {
                    if (q.ID.Equals("suicide"))
                    {
                        // Find the distance between two pigs.
                        float dist = Vector2.Distance(this.position, q.position);

                        // If a suicide pig is within a distance of 150, then move up or down and try to get out of the suicide pig's
                        // death range
                        if (dist < 150)
                        {
                            foundSuicide = true;
                            //If the calling pig has a position Y that is greater than the others, move it in that direction
                            //Otherwise move it in the other y directinon
                            if (this.position.Y > q.position.Y)
                            {
                                if (ObstacleMove(obstacles, "down", this.position).Equals("none"))
                                {
                                    this.position.Y += 5;
                                }
                            }
                            else
                            {
                                if (ObstacleMove(obstacles, "up", this.position).Equals("none"))
                                {
                                    this.position.Y -= 5;
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
